package lg.minecraft.plugin.pokemonmenu.gui;

import com.cobblemon.mod.common.api.pokemon.labels.CobblemonPokemonLabels;
import com.cobblemon.mod.common.api.storage.pc.PCBox;
import com.cobblemon.mod.common.pokemon.Pokemon;
import lg.minecraft.plugin.cobblemoncore.util.BasePokemonUtil;
import lg.minecraft.plugin.library.inventory.CancelInventoryContext;
import lg.minecraft.plugin.library.inventory.ClickInventoryContext;
import lg.minecraft.plugin.library.inventory.InventoryContext;
import lg.minecraft.plugin.library.inventory.LGInventory;
import lg.minecraft.plugin.pokemonmenu.LGPokemonMenu;
import lg.minecraft.plugin.pokemonmenu.PokemonPlayer;
import lg.minecraft.plugin.pokemonmenu.manager.PokemonPlayerManger;
import org.bukkit.entity.Player;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.ToIntFunction;

/**
 * @author langle__
 * @version 1.0
 */
public class SortInventor extends LGInventory {

    private final UUID targetUUID;
    private final int page;

    public SortInventor(UUID targetUUID, int page) {
        super(1, LGPokemonMenu.getMessage().getGuiTitleSort());
        this.targetUUID = targetUUID;
        this.page = page;
    }

    @Override
    public void onInventoryOpen(CancelInventoryContext context) {
        inventory.setItem(0, LGPokemonMenu.getGuiItem().getSortLevel());
        inventory.setItem(1, LGPokemonMenu.getGuiItem().getSortIv());
        inventory.setItem(2, LGPokemonMenu.getGuiItem().getSortBase());
        inventory.setItem(3, LGPokemonMenu.getGuiItem().getSortType());
        inventory.setItem(4, LGPokemonMenu.getGuiItem().getSortGen());
        inventory.setItem(5, LGPokemonMenu.getGuiItem().getSortPokedex());
    }

    @Override
    public void onInventoryClick(ClickInventoryContext context) {
        context.setCancelled(true);
        Player player = context.getPlayer();
        int slot = context.getSlot();

        ToIntFunction<Pokemon> extractor = switch (slot) {
            case 0 -> Pokemon::getLevel;
            case 1 -> BasePokemonUtil::countMaxIvs;
            case 2 -> BasePokemonUtil::getBaseStatSum;
            case 3 -> SortInventor::getClassPriority;
            case 4 -> SortInventor::getGenerationPriority;
            case 5 -> SortInventor::getPokedexNumber;
            default -> throw new IllegalStateException("Unexpected value: " + slot);
        };

        PokemonPlayer pokemonPlayer = PokemonPlayerManger.INSTANCE.getPokemonPlayer(targetUUID);
        PCBox pcBox = pokemonPlayer.getPCStore().getBoxes().get(page);

        List<Pokemon> pokemonList = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            Pokemon pokemon = pcBox.get(i);
            if (pokemon == null) continue;
            pokemonList.add(pokemon);
            pcBox.set(i, null);
        }

        sortPokemonList(pokemonList, extractor);

        // 将排序后的宝可梦放回 PCBox
        for (int i = 0; i < pokemonList.size(); i++) {
            pcBox.set(i, pokemonList.get(i));
        }

        new PCInventor(targetUUID, page).openInventory(player);
    }

    @Override
    public void onInventoryClose(InventoryContext context) {
    }

    public static int getClassPriority(Pokemon pokemon) {
        if (pokemon.hasLabels(CobblemonPokemonLabels.LEGENDARY)) return pokemon.getShiny() ? 99 : 98;
        if (pokemon.hasLabels(CobblemonPokemonLabels.ULTRA_BEAST)) return pokemon.getShiny() ? 97 : 96;
        if (pokemon.hasLabels(CobblemonPokemonLabels.MYTHICAL)) return pokemon.getShiny() ? 95 : 94;
        if (pokemon.hasLabels(CobblemonPokemonLabels.PARADOX)) return pokemon.getShiny() ? 93 : 92;
        return pokemon.getShiny() ? 1 : 0;
    }

    public static int getGenerationPriority(Pokemon pokemon) {
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_1)) return pokemon.getShiny() ? 99 : 98;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_2)) return pokemon.getShiny() ? 97 : 96;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_3)) return pokemon.getShiny() ? 95 : 94;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_4)) return pokemon.getShiny() ? 93 : 92;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_5)) return pokemon.getShiny() ? 91 : 90;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_6)) return pokemon.getShiny() ? 89 : 88;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_7)) return pokemon.getShiny() ? 87 : 86;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_7B)) return pokemon.getShiny() ? 85 : 84;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_8)) return pokemon.getShiny() ? 83 : 82;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_8A)) return pokemon.getShiny() ? 81 : 80;
        if (pokemon.hasLabels(CobblemonPokemonLabels.GENERATION_9)) return pokemon.getShiny() ? 79 : 78;
        return 0;
    }

    public static int getPokedexNumber(Pokemon pokemon) {
        return Integer.MAX_VALUE - pokemon.getSpecies().getNationalPokedexNumber();
    }

    /**
     * 根据自定义数值对宝可梦列表进行排序
     *
     * @param pokemonList      宝可梦列表
     * @param function   获取宝可梦数值的方法
     */
    private static void sortPokemonList(List<Pokemon> pokemonList, ToIntFunction<Pokemon> function) {
        pokemonList.sort((p1, p2) -> Integer.compare(function.applyAsInt(p2), function.applyAsInt(p1)));
    }

}
